using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
using SlimDX;
using SlimDX.Direct3D9;

using System.Xml;
using System.Xml.Serialization;

/// <summary>
/// Enumerator used for switching between the four
/// Splino Panels
/// </summary>
public enum Panels 
{ 
    /// <summary>
    /// The northwest Splino Panel
    /// </summary>
    panelNW,
    /// <summary>
    /// The northeast Splino Panel
    /// </summary>
    panelNE,
    /// <summary>
    /// The southwest Splino Panel
    /// </summary>
    panelSW,
    /// <summary>
    /// The southeast Splino Panel
    /// </summary>
    panelSE,
    /// <summary>
    /// No Splino Panel selected
    /// </summary>
    none 
};

// The main namespace for the Splino application
namespace Splino
{
    // Namespace containing Direct3D functionality
    using Splino.D3D;

    // Namespace containing Splino 3D objects
    using Splino.DrawObject;

    // The main form for the Splino application
    public sealed partial class SplinoForm : Form
    {       
        private List<SplinoWindow> _splinoWindows = new List<SplinoWindow>();
        /// <summary>
        /// Gets the collection of Splino Windows contained in the main form.
        /// </summary>
        public List<SplinoWindow> SplinoWindows
        {
            get { return _splinoWindows; }
        }

        /// <summary>
        /// Gets a collection of of Splino Windows' serializable components
        /// </summary>
        public List<SplinoWindowXML> SplinoWindowsXML
        {
            get
            {
                List<SplinoWindowXML> splinoWindowsXML = new List<SplinoWindowXML>();
                foreach (SplinoWindow splinoWindow in _splinoWindows)
                    splinoWindowsXML.Add(new SplinoWindowXML(splinoWindow));
                return splinoWindowsXML;
            }
        }
        
        SplinoWindow _windowMaxed = null;
        /// <summary>
        /// Gets or sets whether a SplinoPanel is maximized
        /// </summary>
        public SplinoWindow MaximizedWindow
        {
            get { return _windowMaxed; }
            set { _windowMaxed = value; }
        }

        SplinoWindow _windowMouseOver = null;
        /// <summary>
        /// Gets or sets whether the mouse is over a SplinoPanel
        /// </summary>
        public SplinoWindow WindowMouseOver
        {
            get { return _windowMouseOver; }
            set { _windowMouseOver = value; }
        }

        int _fps = 0;
        /// <summary>
        /// Gets or sets the calculated frames per second
        /// </summary>
        public int FPS
        {
            get { return _fps; }
            set { _fps = value; }
        }

        Point _cursorWrapOffset = new Point();
        /// <summary>
        /// Gets the number of pixels the cursor is offset after
        /// it wraps around a SplinoPanel
        /// </summary>
        public Point CursorWrapOffset
        {
            get { return _cursorWrapOffset; }
        }

        Point _cursorStartPosition = new Point();
        /// <summary>
        /// Gets the pixel coordinates of the mouse for tracking
        /// the beginning of a mouse down or similar event
        /// </summary>
        public Point CursorStartPosition
        {
            get { return _cursorStartPosition;}
        }

        Cursor _cursorPan = new Cursor(typeof(SplinoForm), "Resources.Cursors.pan.cur");
        /// <summary>
        /// Gets the mouse cursor used during viewport panning
        /// </summary>
        public Cursor CursorPan
        {
            get { return _cursorPan; }
        }

        Cursor _cursorRotate = new Cursor(typeof(SplinoForm), "Resources.Cursors.rotate.cur");
        /// <summary>
        /// Gets the mouse cursor used during viewport rotating
        /// </summary>
        public Cursor CursorRotate
        {
            get { return _cursorRotate; }
        }

        Cursor _cursorZoom = new Cursor(typeof(SplinoForm), "Resources.Cursors.zoom.cur");
        /// <summary>
        /// Get the mouse cursor used during viewport zooming
        /// </summary>
        public Cursor CursorZoom
        {
            get { return _cursorZoom; }
        }

        Cursor _cursorDraw = new Cursor(typeof(SplinoForm), "Resources.Cursors.draw.cur");
        /// <summary>
        /// Gets the crosshair mouse cursor used during drawing/point selection
        /// </summary>
        public Cursor CursorDraw
        {
            get { return _cursorDraw; }
        }

        bool _keysShift = false;
        /// <summary>
        /// Gets whether the shift key is depressed
        /// </summary>
        public bool KeysShift
        {
            get { return _keysShift; }
        }

        /// <summary>
        /// Gets or sets the label that displays the distance between the
        /// cursor and the drawing base point.
        /// </summary>
        public ToolStripStatusLabel LabelDistance
        {
            get { return _labelDistance; }
            set { _labelDistance = value; }
        }

        /// <summary>
        /// Gets or sets the label text for indicating the X coordinate
        /// of th mouse cursor in 3D space
        /// </summary>
        public String LabelXCoordStatusText
        {
            get { return _labelXCoordStatus.Text; }
            set { _labelXCoordStatus.Text = value; }
        }

        /// <summary>
        /// Gets or sets the label text for indicating the Y coordinate
        /// of the mouse cursor in 3D space
        /// </summary>
        public String LabelYCoordStatusText
        {
            get { return _labelYCoordStatus.Text; }
            set { _labelYCoordStatus.Text = value; }
        }

        /// <summary>
        /// Gets or sets the label text for indicating the Z coordinate
        /// of the mouse cursor in 3D space
        /// </summary>
        public String LabelZCoordStatusText
        {
            get { return _labelZCoordStatus.Text; }
            set { _labelZCoordStatus.Text = value; }
        }

        DialogResult _openFileDialogResult;
        /// <summary>
        /// Gets the Open Fiel Dialog result/filename
        /// </summary>
        public DialogResult OpenFileDialogResult
        {
            get { return _openFileDialogResult; }
        }

        DialogResult _saveFileAsDialogResult;
        /// <summary>
        /// Gets the Save File As Dialog result/filename
        /// </summary>
        public DialogResult SaveFileAsDialogResult
        {
            get { return _saveFileAsDialogResult; }
        }

        /// <summary>
        /// The text to display on the form title bar after
        /// the current filename
        /// </summary>
        String _formText = " - Splino Alpha ";

        String _splinoVersion;
        /// <summary>
        /// The current version of Splino to four decimals
        /// </summary>
        public String VersionLong { get { return _splinoVersion; } }
        /// <summary>
        /// The current version of Splino to two decimals
        /// </summary>
        public String VersionShort 
        { 
            get
            {
                String[] versionSplit = _splinoVersion.Split('.');

                return versionSplit[0] + "." + versionSplit[1];
            } 
        }

        /// <summary>
        /// The filename of the currently opened document
        /// </summary>
        String _currentFilename = "Untitled";

        /// <summary>
        /// Gets or sets the Undo Multiple... ToolStripMenuItem
        /// </summary>
        public ToolStripMenuItem UndoMultipleMenuItem
        {
            get { return _undoMultipleToolStripMenuItem; }
            set { _undoMultipleToolStripMenuItem = value; }
        }

        /// <summary>
        /// Gets or sets the Redo Multiple... ToolStripMenuItem
        /// </summary>
        public ToolStripMenuItem RedoMultipleMenuItem
        {
            get { return _redoMultipleToolStripMenuItem; }
            set { _redoMultipleToolStripMenuItem = value; }
        }

        /// <summary>
        /// Gets or sets the Cut ToolStripMenuItem
        /// </summary>
        public ToolStripMenuItem CutMenuItem
        {
            get { return _cutToolStripMenuItem; }
            set { _cutToolStripMenuItem = value; }
        }

        /// <summary>
        /// Gets or sets the Copy ToolStripMenuItem
        /// </summary>
        public ToolStripMenuItem CopyMenuItem
        {
            get { return _copyToolStripMenuItem; }
            set { _copyToolStripMenuItem = value; }
        }

        /// <summary>
        /// Gets or sets the Paste ToolStripMenuItem
        /// </summary>
        public ToolStripMenuItem PasteMenuItem
        {
            get { return _pasteToolStripMenuItem; }
            set { _pasteToolStripMenuItem = value; }
        }

        /// <summary>
        /// Gets or sets the Delete ToolSDtripMenuItem
        /// </summary>
        public ToolStripMenuItem DeleteMenuItem
        {
            get { return _deleteToolStripMenuItem; }
            set { _deleteToolStripMenuItem = value; }
        }

        bool _gridSnapSelected;
        /// <summary>
        /// Gets whether grid snapping is on or off.
        /// </summary>
        public bool GridSnapSelected { get { return _gridSnapSelected; } }

        float _gridSnapDistance;
        /// <summary>
        /// Gets a float representing the horizontal and vertical.
        /// distance between grid snaps
        /// </summary>
        public float GridSnapDistance 
        { 
            get { return _gridSnapDistance; }
            set
            {
                _gridSnapDistance = value;
                _gridUnitsNumeric.Value = (decimal)value;
            }
        }

        bool _angleSnapSelected;
        /// <summary>
        /// Gets or sets whether angle snapping is on or off.
        /// </summary>
        public bool AngleSnapSelected { get { return _angleSnapSelected; } }

        float _angleSnapDegrees;
        /// <summary>
        /// Gets a float representing the number of degrees between angle snaps
        /// </summary>
        public float AngleSnapDegrees 
        { 
            get { return _angleSnapDegrees; }
            set
            {
                _angleSnapDegrees = value;
                _angleDegreesNumeric.Value = (decimal)value;
            }
        }

        bool _objectSnapSelected;
        /// <summary>
        /// Gets whether object snapping is on or off.
        /// </summary>
        public bool ObjectSnapSelected { get { return _objectSnapSelected; } }

        bool _objectEndSnapSelected;
        /// <summary>
        /// Gets whether object endpoint snapping is on or off.
        /// </summary>
        public bool ObjectEndSnapSelected { get { return _objectEndSnapSelected; } }

        bool _objectNearSnapSelected;
        /// <summary>
        /// Gets whether near to object snapping is on or off.
        /// </summary>
        public bool ObjectNearSnapSelected { get { return _objectNearSnapSelected; } }

        bool _objectPointSnapSelected;
        /// <summary>
        /// Gets whether point object snapping is on or off.
        /// </summary>
        public bool ObjectPointSnapSelected { get { return _objectPointSnapSelected; } }

        bool _objectMidSnapSelected;
        /// <summary>
        /// Gets whether object midpoint snapping is on or off.
        /// </summary>
        public bool ObjectMidSnapSelected { get { return _objectMidSnapSelected; } }

        bool _objectCenterSnapSelected;
        /// <summary>
        /// Gets whether object center snapping is on or off.
        /// </summary>
        public bool ObjectCenterSnapSelected { get { return _objectCenterSnapSelected; } }

        bool _objectIntersectSnapSelected;
        /// <summary>
        /// Gets whether object intersection snapping is on or off.
        /// </summary>
        public bool ObjectIntersectSnapSelected { get { return _objectIntersectSnapSelected; } }

        bool _objectPerpSnapSelected;
        /// <summary>
        /// Gets whether perpendicular to object snapping is on or off.
        /// </summary>
        public bool ObjectPerpSnapSelected { get { return _objectPerpSnapSelected; } }

        bool _objectTanSnapSelected;
        /// <summary>
        /// Gets whether tangent to object snapping is on or off.
        /// </summary>
        public bool ObjectTanSnapSelected { get { return _objectTanSnapSelected; } }

        bool _objectQuadrantSnapSelected;
        /// <summary>
        /// Gets whether object quadrant snapping is on or off.
        /// </summary>
        public bool ObjectQuadrantSnapSelected { get { return _objectQuadrantSnapSelected; } }

        bool _objectCloseSplineSnapSelected = false;
        /// <summary>
        /// Gets or sets whether snap to spline endpoint (making a closed spline) is active not controlled via UI.
        /// </summary>
        public bool ObjectCloseSplineSnapSelected { 
            get { return _objectCloseSplineSnapSelected; }
            set { _objectCloseSplineSnapSelected = value; }
        }

        /// <summary>
        /// Adds the main menu bar and Splino toolstrip heights onto a point in the client area of the form.
        /// </summary>
        /// <param name="point">The point to adjust for the toolbars</param>
        /// <returns></returns>
        public Point PointToMDIClientArea(Point point)
        {
            return new Point(
                point.X,
                point.Y + menuStripMainMenu.Height + splinoToolStrip.Height);
        }

        /// <summary>
        /// Gets whether Splino is in continuous rendering mode.
        /// </summary>
        public bool ContinuousRenderingMode { get { return _continuousToolStripItem.Checked; } }

        private static readonly object padlock = new object();
        private static volatile SplinoForm _instance;
        /// <summary>
        /// The singleton instance of the SplinoForm class.
        /// </summary>
        public static SplinoForm Instance 
        { 
            get 
            {
                if (_instance == null)
                    lock (padlock) 
                    {
                        if (_instance == null)
                            _instance = new SplinoForm(); 
                    }
                return _instance; 
            } 
        }

        private SplinoForm()
        {
            InitializeComponent();

            CreateDefaultSplinoWindows();

            _splinoVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();

            newToolStripMenuItem.Image = newToolStripButton.Image;
            openToolStripMenuItem.Image = openToolStripButton.Image;
            saveToolStripMenuItem.Image = saveToolStripButton.Image;

            _copyToolStripMenuItem.Image = copyToolStripButton.Image;
            _cutToolStripMenuItem.Image = cutToolStripButton.Image;
            _pasteToolStripMenuItem.Image = pasteToolStripButton.Image;
            _deleteToolStripMenuItem.Image = SplinoImageList.Instance.Images["Delete"];
            _undoToolStripMenuItem.Image = SplinoImageList.Instance.Images["Undo"];
            _redoToolStripMenuItem.Image = SplinoImageList.Instance.Images["Redo"];
            _sceneManagerToolStripMenuItem.Image = SplinoImageList.Instance.Images["SceneManagerTree"];
            _commandPromptToolStripMenuItem.Image = SplinoImageList.Instance.Images["CommandPrompt"];

            this.Text = _currentFilename + this._formText + VersionShort.ToString();

            this.MouseWheel += new MouseEventHandler(SplinoForm_MouseWheel);

            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);

            IDataObject dataObject = Clipboard.GetDataObject();
            if (dataObject.GetDataPresent(typeof(SplinoObject)))
                PasteMenuItem.Enabled = true;

            if (_gridSnapCheckBox.Checked)
            {
                _gridSnapSelected = true;
                _gridUnitsNumeric.Enabled = true;
            }
            else
            {
                _gridSnapSelected = false;
                _gridUnitsNumeric.Enabled = false;
            }
            _gridSnapDistance = (float)_gridUnitsNumeric.Value;

            if (_angleCheckBox.Checked)
            {
                _angleSnapSelected = true;
                _angleDegreesNumeric.Enabled = true;
            }
            else
            {
                _angleSnapSelected = false;
                _angleDegreesNumeric.Enabled = false;
            }
            _angleSnapDegrees = (float)_angleDegreesNumeric.Value;

            if (_objectCheckBox.Checked)
            {
                _objectSnapSelected = true;

                _endCheckBox.Enabled = true;
                _pointCheckBox.Enabled = true;
                _nearCheckBox.Enabled = true;
                _tanCheckBox.Enabled = true;
                _perpCheckBox.Enabled = true;
                _centerCheckBox.Enabled = true;
                _midCheckBox.Enabled = true;
                _intersectCheckBox.Enabled = true;
                _quadrantCheckBox.Enabled = true;

                _objectEndSnapSelected = _endCheckBox.Checked;
                _objectPointSnapSelected = _pointCheckBox.Checked;
                _objectNearSnapSelected = _nearCheckBox.Checked;
                _objectTanSnapSelected = _tanCheckBox.Checked;
                _objectPerpSnapSelected = _perpCheckBox.Checked;
                _objectCenterSnapSelected = _centerCheckBox.Checked;
                _objectMidSnapSelected = _midCheckBox.Checked;
                _objectIntersectSnapSelected = _intersectCheckBox.Checked;
                _objectQuadrantSnapSelected = _quadrantCheckBox.Checked;
            }
            else
            {
                _objectSnapSelected = false;

                _endCheckBox.Enabled = false;
                _pointCheckBox.Enabled = false;
                _nearCheckBox.Enabled = false;
                _tanCheckBox.Enabled = false;
                _perpCheckBox.Enabled = false;
                _centerCheckBox.Enabled = false;
                _midCheckBox.Enabled = false;
                _intersectCheckBox.Enabled = false;
                _quadrantCheckBox.Enabled = false;

                _objectEndSnapSelected = false;
                _objectPointSnapSelected = false;
                _objectNearSnapSelected = false;
                _objectTanSnapSelected = false;
                _objectPerpSnapSelected = false;
                _objectCenterSnapSelected = false;
                _objectMidSnapSelected = false;
                _objectIntersectSnapSelected = false;
                _objectQuadrantSnapSelected = false;
            }
        }

        /// <summary>
        /// Creates the four default Splino Windows
        /// </summary>
        public void CreateDefaultSplinoWindows()
        {
            CreateSplinoWindow();
            CreateSplinoWindow();
            CreateSplinoWindow();
            CreateSplinoWindow();

            LayoutSplinoWindows();
        }

        /// <summary>
        /// Creates and shows a new, docked Splino Window
        /// </summary>
        /// <returns>The newly created Splino Window</returns>
        public SplinoWindow CreateSplinoWindow()
        {
            SplinoWindow splinoWindow = new SplinoWindow();
            SplinoWindows.Add(splinoWindow);
            splinoWindow.SplinoFormChild.MdiParent = this;
            splinoWindow.MdiParent = this;
            splinoWindow.Docked = true;
            if (CommandManager.Initialized)
                CommandManager.Instance.RegisterSplinoWindow(splinoWindow);
            splinoWindow.SplinoFormChild.Show();
            splinoWindow.Show();
            return splinoWindow;
        }

        /// <summary>
        /// Sets the height, width, and location of the four Splino Panels
        /// </summary>
        public void Position3DWindows()
        {
            List<SplinoViewport> dockedViewports = new List<SplinoViewport>();
            List<SplinoViewport> maximizedViewports = new List<SplinoViewport>();

            foreach (SplinoWindow splinoWindow in SplinoWindows)
            {
                if (splinoWindow.Docked && splinoWindow.WindowState == FormWindowState.Normal
                    && splinoWindow.SplinoViewport != null)
                    dockedViewports.Add(splinoWindow.SplinoViewport);
                else if (splinoWindow.Docked && splinoWindow.WindowState == FormWindowState.Maximized
                    && splinoWindow.SplinoViewport != null)
                    maximizedViewports.Add(splinoWindow.SplinoViewport);
            }

            if (maximizedViewports.Count > 0)
            {
                foreach (SplinoViewport splinoViewport in dockedViewports)
                    if (splinoViewport.ViewportWindow.WindowState == FormWindowState.Normal)
                        splinoViewport.Paused = true;
            }
            else
            {
                foreach (SplinoViewport splinoViewport in dockedViewports)
                {
                    splinoViewport.ResizeSwapChain();
                    splinoViewport.Paused = false;
                    splinoViewport.ViewportWindow.Location = new Point(
                        splinoViewport.ViewportWindow.SplinoFormChild.Location.X,
                        splinoViewport.ViewportWindow.SplinoFormChild.Location.Y);
                }
            }
        }

        /// <summary>
        /// Lays out the docked Splino Windows as MDI Children
        /// </summary>
        public void LayoutSplinoWindows()
        {
            LayoutMdi(MdiLayout.TileHorizontal);
            //foreach (SplinoWindow splinoWindow in SplinoWindows)
            //    if (splinoWindow.Docked)
            //        splinoWindow.Location = new Point(
            //            splinoWindow.SplinoFormChild.Location.X,
            //            splinoWindow.SplinoFormChild.Location.Y);
        }

        private void exitToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.Exit());
        }

        private void SplinoForm_ResizeBegin(object sender, EventArgs e)
        {
            DeviceManager.Instance.PauseRenderer();
        }

        private void SplinoForm_Resize(object sender, EventArgs e)
        {
            LayoutMdi(MdiLayout.TileHorizontal);
            Position3DWindows();
            if (DeviceManager.Initialized && !DeviceManager.Instance.DevicePaused)
                DeviceManager.Instance.Reset();
        }

        private void SplinoForm_ResizeEnd(object sender, EventArgs e)
        {
            if (DeviceManager.Instance.DevicePaused)
                DeviceManager.Instance.Reset();
            DeviceManager.Instance.UnpauseRenderer();
        }

        private void SplinoForm_Paint(object sender, PaintEventArgs e)
        {
            DeviceManager.Instance.Render();
        }

        /// <summary>
        /// Resets the point cursor status text
        /// </summary>
        public void ResetCoordStatusText()
        {
            _labelXCoordStatus.Text = "x 0.000";
            _labelYCoordStatus.Text = "y 0.000";
            _labelZCoordStatus.Text = "z 0.000";
        }

        /// <summary>
        /// Key Down event handler
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Event arguments</param>
        public void SplinoForm_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.ShiftKey:
                    _keysShift = true;
                    break;
            }
            if (!e.Control && !e.Alt && !e.Shift && e.KeyValue >= 65 && e.KeyValue <= 90)
            {
                CommandManager.Instance.ShowCommandPrompt();
                CommandManager.Instance.CommandPrompt.TextBoxInput.Text = e.KeyCode.ToString();
                CommandManager.Instance.CommandPrompt.TextBoxInput.SelectionStart = 1;
            }
        }

        /// <summary>
        /// Key Up event handler
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Key event arguments</param>
        public void SplinoForm_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.ShiftKey:
                    _keysShift = false;
                    break;
            }
        }

        /// <summary>
        /// Updates the status bar label text that indicates how
        /// many frames per second Splino is currently rendering at
        /// </summary>
        public void UpdateFPS()
        {
            _labelFPS.Text = _fps + " Frames Per Second";
        }

        private void buttonMouseModeNormal_Click(object sender, EventArgs e)
        {
            
        }

        private void buttonMouseModePan_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.PanCamera());
        }

        private void buttonMouseModeZoo_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.ZoomCamera());
        }

        private void buttonMouseModeRotate_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.RotateCamera());
        }

        private void commandPromptToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ShowCommandPrompt();
        }

        private void SplinoForm_MouseWheel(object sender, MouseEventArgs e)
        {
            _windowMouseOver.SplinoWindow_MouseWheel(null, e);
        }

        private void redoViewChangeToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.RedoViewChange());
        }

        private void undoViewChangeToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.UndoViewChange());
        }

        private void drawCurvesToolStripMenuIte_Click(object sender, EventArgs e)
        {
            DrawManager.Instance.ShowDrawToolbar();
        }

        private void undoToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.Undo());
        }

        private void redoToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.Redo());
        }

        private void SplinoForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.WindowState = this.WindowState;

            if (WindowState == FormWindowState.Normal)
            {
                Properties.Settings.Default.SplinoFormSize = this.Size;
                Properties.Settings.Default.SplinoFormLocation = this.Location;
            }
            else
            {
                Properties.Settings.Default.SplinoFormSize = this.RestoreBounds.Size;
                Properties.Settings.Default.SplinoFormLocation = this.RestoreBounds.Location;
            }
            Properties.Settings.Default.AsNeededCheckState = this._asNeededToolStripMenuItem.CheckState;
            Properties.Settings.Default.ContinuousCheckState = this._continuousToolStripItem.CheckState;

            Properties.Settings.Default.Save();
        }

        private void sceneManagerToolStripMenuIte_Click(object sender, EventArgs e)
        {
            SceneManager.Instance.ShowSceneManagerTree();
        }

        private void SplinoForm_Load(object sender, EventArgs e)
        {
            this.Size = Properties.Settings.Default.SplinoFormSize;
            this.Location = Properties.Settings.Default.SplinoFormLocation;
            this.WindowState = Properties.Settings.Default.WindowState;
            _asNeededToolStripMenuItem.CheckState = Properties.Settings.Default.AsNeededCheckState;
            _continuousToolStripItem.CheckState = Properties.Settings.Default.ContinuousCheckState;
            if (_asNeededToolStripMenuItem.Checked)
            {
                _labelFPS.Text = string.Empty;
                _renderModeDropDown.Text = "Rendering Mode: As Needed";
            }
            else
                _renderModeDropDown.Text = "Rendering Mode: Continuous";

            DeviceManager.Instance.SetupDefaultViewports();
            SceneManager sceneManager = SceneManager.Instance;

            Position3DWindows();
            foreach (SplinoWindow splinoWindow in _splinoWindows)
                splinoWindow.Initialized = true;
        }

        private void saveToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.Save());
        }

        private void openToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.Open());
        }

        /// <summary>
        /// Resets the SplinoForm variables, and reinitializes the DeviceManager,
        /// SceneManager, and CommandManager
        /// </summary>
        public void NewFile()
        {
            _windowMaxed = null;

            Position3DWindows();

            DeviceManager.Instance.ClearDeviceManager();
            SceneManager.Instance.ClearSceneManager();
            CommandManager.Instance.ClearCommandManager();

            List<SplinoWindow> splinoWindows = new List<SplinoWindow>();
            foreach (SplinoWindow splinoWindow in _splinoWindows)
                splinoWindows.Add(splinoWindow);
            foreach (SplinoWindow splinoWindow in splinoWindows)
                splinoWindow.Close();
            splinoWindows.Clear();
            _splinoWindows.Clear();

            CreateDefaultSplinoWindows();

            DeviceManager.Instance.SetupDefaultViewports();
            SceneManager sceneManager = SceneManager.Instance;

            _currentFilename = "Untitled";
            this.Text = _currentFilename + this._formText + VersionShort.ToString();
        }

        private void newToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.New());
        }

        /// <summary>
        /// Shows the open file dialogue, opens the file, and saves the current filename
        /// </summary>
        public void OpenFile()
        {
            _openFileDialogResult = _openFileDialog.ShowDialog();
            if (_openFileDialogResult == DialogResult.OK)
            {
                SplinoXML.OpenFile(_openFileDialog.FileName);
                _currentFilename = Path.GetFileName(_openFileDialog.FileName);
                this.Text = _currentFilename + this._formText + VersionShort.ToString();
            }
        }

        /// <summary>
        /// Saves the file to the current filename
        /// </summary>
        public void SaveFile()
        {
            if (_currentFilename == "Untitled")
                SaveFileAs();
            else
                SplinoXML.SaveFile(_currentFilename);
        }

        /// <summary>
        /// Shows the Save File As dialogue and saves the file to that filename
        /// </summary>
        public void SaveFileAs()
        {
            _saveFileDialog.FileName = _currentFilename;
            _saveFileAsDialogResult = _saveFileDialog.ShowDialog();
            if (_saveFileAsDialogResult == DialogResult.OK)
            {
                SplinoXML.SaveFile(_saveFileDialog.FileName);
                _currentFilename = Path.GetFileName(_saveFileDialog.FileName);
                this.Text = _currentFilename + this._formText + VersionShort.ToString();
            }

        }

        private void saveAsToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.SaveAs());
        }

        /// <summary>
        /// Closes the SplinoForm, exiting the application
        /// </summary>
        public void Exit()
        {
            this.Close();
        }

        private void newToolStripButton_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.New());
        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.Open());
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.Save());
        }

        private void AllToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.SelectAll());
        }

        private void NoneStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.SelectNone());
        }

        private void invertToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.InvertSelection());
        }

        private void _undoMultipleToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.UndoMultiple());
        }

        private void _redoMultipleToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.RedoMultiple());
        }

        private void _deleteToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.Delete());
        }

        private void _copyToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.CopyClipboard());
        }

        private void _pasteToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.PasteClipboard());
        }

        private void cutToolStripButton_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.CutClipboard());
        }

        private void copyToolStripButton_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.CopyClipboard());
        }

        private void pasteToolStripButton_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.PasteClipboard());
        }

        private void _cutToolStripMenuIte_Click(object sender, EventArgs e)
        {
            CommandManager.Instance.ExecuteCommand(new Commands.CutClipboard());
        }

        /// <summary>
        /// Toggles grid snapping
        /// </summary>
        public void Command_GridSnap()
        {
            if (!_gridSnapSelected)
            {
                _gridSnapCheckBox.Checked = true;
                _gridSnapSelected = true;
                _gridUnitsNumeric.Enabled = true;
            }
            else
            {
                _gridSnapCheckBox.Checked = false;
                _gridSnapSelected = false;
                _gridUnitsNumeric.Enabled = false;
            }
        }

        /// <summary>
        /// Toggles angle snapping
        /// </summary>
        public void Command_AngleSnap()
        {
            if (!_angleSnapSelected)
            {
                _angleCheckBox.Checked = true;
                _angleSnapSelected = true;
                _angleDegreesNumeric.Enabled = true;
            }
            else
            {
                _angleCheckBox.Checked = false;
                _angleSnapSelected = false;
                _angleDegreesNumeric.Enabled = false;
            }
        }

        /// <summary>
        /// Toggles object snapping
        /// </summary>
        public void Command_ObjectSnap()
        {
            if (!_objectSnapSelected)
            {
                _objectCheckBox.Checked = true;
                _objectSnapSelected = true;

                _endCheckBox.Enabled = true;
                _pointCheckBox.Enabled = true;
                _nearCheckBox.Enabled = true;
                _tanCheckBox.Enabled = true;
                _perpCheckBox.Enabled = true;
                _centerCheckBox.Enabled = true;
                _midCheckBox.Enabled = true;
                _intersectCheckBox.Enabled = true;
                _quadrantCheckBox.Enabled = true;

                _objectEndSnapSelected = _endCheckBox.Checked;
                _objectPointSnapSelected = _pointCheckBox.Checked;
                _objectNearSnapSelected = _nearCheckBox.Checked;
                _objectTanSnapSelected = _tanCheckBox.Checked;
                _objectPerpSnapSelected = _perpCheckBox.Checked;
                _objectCenterSnapSelected = _centerCheckBox.Checked;
                _objectMidSnapSelected = _midCheckBox.Checked;
                _objectIntersectSnapSelected = _intersectCheckBox.Checked;
                _objectQuadrantSnapSelected = _quadrantCheckBox.Checked;
            }
            else
            {
                _objectCheckBox.Checked = false;
                _objectSnapSelected = false;

                _endCheckBox.Enabled = false;
                _pointCheckBox.Enabled = false;
                _nearCheckBox.Enabled = false;
                _tanCheckBox.Enabled = false;
                _perpCheckBox.Enabled = false;
                _centerCheckBox.Enabled = false;
                _midCheckBox.Enabled = false;
                _intersectCheckBox.Enabled = false;
                _quadrantCheckBox.Enabled = false;

                _objectEndSnapSelected = false;
                _objectPointSnapSelected = false;
                _objectNearSnapSelected = false;
                _objectTanSnapSelected = false;
                _objectPerpSnapSelected = false;
                _objectCenterSnapSelected = false;
                _objectMidSnapSelected = false;
                _objectIntersectSnapSelected = false;
                _objectQuadrantSnapSelected = false;
            }
        }

        /// <summary>
        /// Toggles object end point snapping
        /// </summary>
        public void Command_ObjectEndSnap()
        {
            if (!_objectEndSnapSelected)
            {
                _endCheckBox.Checked = true;
                _objectEndSnapSelected = true;
            }
            else
            {
                _endCheckBox.Checked = false;
                _objectEndSnapSelected = false;
            }
        }

        /// <summary>
        /// Toggles near to object snapping
        /// </summary>
        public void Command_ObjectNearSnap()
        {
            if (!_objectNearSnapSelected)
            {
                _objectNearSnapSelected = true;
                _nearCheckBox.Checked = true;
            }
            else
            {
                _objectNearSnapSelected = false;
                _nearCheckBox.Checked = false;
            }
        }

        /// <summary>
        /// Toggles point object snapping
        /// </summary>
        public void Command_ObjectPointSnap()
        {
            if (!_objectPointSnapSelected)
            {
                _objectPointSnapSelected = true;
                _pointCheckBox.Checked = true;
            }
            else
            {
                _objectPointSnapSelected = false;
                _pointCheckBox.Checked = false;
            }
        }

        /// <summary>
        /// Toggles object midpoint snapping
        /// </summary>
        public void Command_ObjectMidSnap()
        {
            if (!_objectMidSnapSelected)
            {
                _objectMidSnapSelected = true;
                _midCheckBox.Checked = true;
            }
            else
            {
                _objectMidSnapSelected = false;
                _midCheckBox.Checked = false;
            }
        }

        /// <summary>
        /// Toggles object center snapping
        /// </summary>
        public void Command_ObjectCenterSnap()
        {
            if (!_objectCenterSnapSelected)
            {
                _objectCenterSnapSelected = true;
                _centerCheckBox.Checked = true;
            }
            else
            {
                _objectCenterSnapSelected = false;
                _centerCheckBox.Checked = false;
            }
        }

        /// <summary>
        /// Toggles object intersection snapping
        /// </summary>
        public void Command_ObjectIntersectSnap()
        {
            if (!_objectIntersectSnapSelected)
            {
                _objectIntersectSnapSelected = true;
                _intersectCheckBox.Checked = true;
            }
            else
            {
                _objectIntersectSnapSelected = false;
                _intersectCheckBox.Checked = false;
            }
        }

        /// <summary>
        /// Toggles perpendicular to object snapping
        /// </summary>
        public void Command_ObjectPerpSnap()
        {
            if (!_objectPerpSnapSelected)
            {
                _objectPerpSnapSelected = true;
                _perpCheckBox.Checked = true;
            }
            else
            {
                _objectPerpSnapSelected = false;
                _perpCheckBox.Checked = false;
            }
        }

        /// <summary>
        /// Toggles tangent to object snapping
        /// </summary>
        public void Command_ObjectTanSnap()
        {
            if (!_objectTanSnapSelected)
            {
                _objectTanSnapSelected = true;
                _tanCheckBox.Checked = true;
            }
            else
            {
                _objectTanSnapSelected = false;
                _tanCheckBox.Checked = false;
            }
        }

        /// <summary>
        /// Toggles object quadrant snapping
        /// </summary>
        public void Command_ObjectQuadrantSnap()
        {
            if (!_objectQuadrantSnapSelected)
            {
                _objectQuadrantSnapSelected = true;
                _quadrantCheckBox.Checked = true;
            }
            else
            {
                _objectQuadrantSnapSelected = false;
                _quadrantCheckBox.Checked = false;
            }
        }


        private void aboutSplinoToolStripMenuIte_Click(object sender, EventArgs e)
        {
            SplinoAboutBox splinoAboutBox = new SplinoAboutBox();
            splinoAboutBox.ShowDialog(this);
        }

        private void _objectCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
                typeof(Commands.ObjectSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectSnap());
        }

        private void _angleCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
                typeof(Commands.AngleSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.AngleSnap());
        }

        private void _gridSnapCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
                typeof(Commands.GridSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.GridSnap());
        }

        private void _gridUnitsNumeric_ValueChanged(object sender, EventArgs e)
        {
            GridSnapDistance = (float)_gridUnitsNumeric.Value;
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
                typeof(Commands.GridSnapUnits_System))
                CommandManager.Instance.ExecuteCommand(new Commands.GridSnapUnits_System());
        }

        private void _angleNumeric_ValueChanged(object sender, EventArgs e)
        {
            AngleSnapDegrees = (float)_angleDegreesNumeric.Value;

            foreach (SplinoViewport splinoViewport in DeviceManager.Instance.Viewports)
                splinoViewport.ComputeAngleSnapPoints();

            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
                typeof(Commands.AngleSnapDegrees_System))
                CommandManager.Instance.ExecuteCommand(new Commands.AngleSnapDegrees_System());
        }

        private void _endCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
                typeof(Commands.ObjectEndSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectEndSnap());
        }

        private void _nearCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
                typeof(Commands.ObjectNearSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectNearSnap());
        }

        private void _pointCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
                typeof(Commands.ObjectPointSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectPointSnap());
        }

        private void _midCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
            typeof(Commands.ObjectMidSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectMidSnap());
        }

        private void _centerCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
            typeof(Commands.ObjectCenterSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectCenterSnap());
        }

        private void _intersectCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
            typeof(Commands.ObjectIntersectSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectIntersectSnap());
        }

        private void _perpCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
            typeof(Commands.ObjectPerpSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectPerpSnap());
        }

        private void _tanCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
            typeof(Commands.ObjectTanSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectTanSnap());
        }

        private void _quadrantCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CommandManager.Instance.ActiveCommandStack.Peek().GetType() !=
            typeof(Commands.ObjectQuadrantSnap))
                CommandManager.Instance.ExecuteCommand(new Commands.ObjectQuadrantSnap());
        }

        private void _asNeededToolStripMenuIte_Click(object sender, EventArgs e)
        {
            if (_asNeededToolStripMenuItem.Checked)
            {
                _continuousToolStripItem.Checked = false;
                _labelFPS.Text = String.Empty;
                _renderModeDropDown.Text = "Rendering Mode: As Needed";
            }
            else
            {
                _continuousToolStripItem.Checked = true;
                _renderModeDropDown.Text = "Rendering Mode: Continuous";
            }
        }

        private void _continuousToolStripIte_Click(object sender, EventArgs e)
        {
            if (_continuousToolStripItem.Checked)
            {
                _asNeededToolStripMenuItem.Checked = false;
                _renderModeDropDown.Text = "Rendering Mode: Continuous";
            }
            else
            {
                _asNeededToolStripMenuItem.Checked = true;
                _labelFPS.Text = string.Empty;
                _renderModeDropDown.Text = "Rendering Mode: As Needed";
            }
        }

        /// <summary>
        /// True if the object snap of the passed in type is checked on the Splino Form.
        /// </summary>
        /// <param name="objectSnapType">The object snap type to test for active state.</param>
        /// <returns>True if the passed in snap type is checked on the Splino Form</returns>
        public bool ObjectSnapTypeActive(ObjectSnapType objectSnapType)
        {
            switch (objectSnapType)
            {
                case ObjectSnapType.End:
                    if (ObjectEndSnapSelected)
                        return true;
                    break;
                case ObjectSnapType.Center:
                    if (ObjectCenterSnapSelected)
                        return true;
                    break;
                case ObjectSnapType.Intersect:
                    if (ObjectIntersectSnapSelected)
                        return true;
                    break;
                case ObjectSnapType.Mid:
                    if (ObjectMidSnapSelected)
                        return true;
                    break;
                case ObjectSnapType.Near:
                    if (ObjectNearSnapSelected)
                        return true;
                    break;
                case ObjectSnapType.Perp:
                    if (ObjectPerpSnapSelected)
                        return true;
                    break;
                case ObjectSnapType.Point:
                    if (ObjectPointSnapSelected)
                        return true;
                    break;
                case ObjectSnapType.Quadrant:
                    if (ObjectQuadrantSnapSelected)
                        return true;
                    break;
                case ObjectSnapType.Tan:
                    if (ObjectTanSnapSelected)
                        return true;
                    break;
                case ObjectSnapType.CloseSpline:
                    if (ObjectCloseSplineSnapSelected)
                        return true;
                    break;
            }
            return false;

        }
    }
}